Conversation
|
✅ Preview binaries are ready! To test with modules: |
mafredri
left a comment
There was a problem hiding this comment.
Nice work so far! I left a few comments and suggestions. Mainly about moving some concerns from httpapi to cmd/server. I think it would be helpful to have some tests based on real agent session restoration output to evaluate the screentracker changes.
lib/httpapi/server.go
Outdated
| currentStatus = st.ConversationStatusChanging | ||
| s.logger.Info("Initial prompt sent successfully") | ||
| if !s.stateLoadComplete && s.statePersistenceCfg.LoadState { | ||
| _, _ = s.conversation.LoadState(s.statePersistenceCfg.StateFile) |
There was a problem hiding this comment.
Not objecting, just curious. Why do we wait for stability to load the state?
There was a problem hiding this comment.
This is by design. We wait for the initial stable state to capture a baseline screen snapshot. This baseline allows us to clear any agent-generated messages or screen content before loading our saved state.
| func (s *Server) HandleSignals(ctx context.Context, process *termexec.Process) { | ||
| // Handle shutdown signals (SIGTERM, SIGINT only on Windows) | ||
| shutdownCh := make(chan os.Signal, 1) | ||
| signal.Notify(shutdownCh, os.Interrupt, syscall.SIGTERM) |
There was a problem hiding this comment.
Does this compile on Windows? IIRC we can only support os.Interrupt there.
There was a problem hiding this comment.
compiles - yes (since PR Preview Build / Build Release Binaries (pull_request) passes), but haven't tested it.
# Conflicts: # cmd/server/server.go # lib/httpapi/server.go # lib/screentracker/conversation.go # lib/screentracker/pty_conversation.go # lib/screentracker/pty_conversation_test.go
# Conflicts: # lib/httpapi/server.go # lib/screentracker/pty_conversation.go
mafredri
left a comment
There was a problem hiding this comment.
Test coverage seems good, but I would really like to see real testdata created for e.g. Claude where all output from the initial conversation, and then again for the restoration part. And testing that AgentAPI does in fact handle this correctly.
I'm not sure how feasible it is, but ideally it'd be nice to capture everything, including control characters, that Claude outputs. Think asciinema recording.
Also, I think we need to really consider everything that can affect the AI agent output. For instance, given the nature of adjustScreenAfterStateLoad, what if --term-height and --term-width have been adjusted between invocations? If the state is being restored, we should probably do so much earlier (in runServer) and print warnings that these options are being overridden by the state restoration and forcing the previous options. Wdyt?
| // Store the first stable snapshot for filtering later | ||
| snapshots := c.snapshotBuffer.GetAll() | ||
| if len(snapshots) > 0 { | ||
| c.firstStableSnapshot = c.cfg.FormatMessage(strings.TrimSpace(snapshots[len(snapshots)-1].screen), "") |
There was a problem hiding this comment.
I suppose we need a FormatMessage nil check here?
Also, what if FormatMessage function has changed between session save and restore (different AgentAPI versions). Potential issue?
| Content: agentState.InitialPrompt, | ||
| Alias: "", | ||
| Hidden: false, | ||
| }} |
There was a problem hiding this comment.
This is probably fine, but asking. Is there a chance that AgentAPI is started with a "new" initial prompt on next start? Should we take that into account instead of overwriting this one?
Do we need to track original prompt separately or can we just discard it from the state? Is it an important component?
|
|
||
| // Before the first user message after loading state, return the last message from the loaded state. | ||
| // This prevents computing incorrect diffs from the restored screen, as the agent's message should | ||
| // remain stable until the user continues the conversation. |
There was a problem hiding this comment.
Asked elsewhere too, but can a "new" initial prompt be provided on startup and does that interfere with this logic?
| return xerrors.Errorf("failed to unmarshal state (corrupted or invalid JSON): %w", err) | ||
| } | ||
|
|
||
| //c.cfg.initialPromptSent = agentState.InitialPromptSent |
Closes: coder/internal#1256
MergeAfter: #172